<html>
    <head>
        <meta charset="utf-8">
        <title>canvas-demo</title>
        <style>
            *{
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <canvas id="canvas"></canvas>
    </body>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script type="text/javascript">
        class Map
        {
            constructor()
            {
                // 获取画布
                this.canvas = document.getElementById("canvas");
                this.ctx = this.canvas.getContext("2d");

                // 获取游戏数据
                let that = this;
                $.get('mapdata.json', function (result) {
                    // 赋值数据
                    that.data = result.mapdata;
                    // 绘制图像
                    that.drawMap();
                }, 'json');
            }

            // 绘制图像
            drawMap()
            {
                // init参数
                this.initData()

                // 绘制场地
                this.createMap()
                // 绘制跑道
                this.createRound()
                // 处理点和圆
                this.createArc()

                let that = this;
                // 监听事件
                this.canvas.addEventListener("click", function (evt) {
                    var mousePos = that.getMousePos(canvas, evt),
                        pagex=mousePos.x,
                        pagey=mousePos.y,
                        // 获取数据
                        arcData = that.handleArcData();

                    // 点击点
                    for(var item of arcData) {
                        if (pagex > item.x1 && pagex < item.x2 && pagey > item.y1 && pagey < item.y2) {
                            console.log('点击数据：', item.data)
                        }
                    }
                }, false);
            }

            // init参数
            initData()
            {
                // 图像宽度
                this.canvas.width = $(window).width()
                var mw = 1200,
                mh = 600,
                lineh = 50,
                greenArcR = 8,
                whiteArcR = 4;

                // 尺寸比例
                this.mapScale = this.canvas.width / mw;
                // 图像高度
                this.canvas.height = this.mapScale * mh;
                // 分割线高度
                this.lineh = this.mapScale * lineh;
                // 分割线宽度
                this.linew = this.lineh * 2;
                // 分割线颜色
                this.lineColor = '#EEEEEE';
                // 分割线宽度
                this.lineWidth = 1;
                // 跑道宽度
                this.roundW = this.lineh * 1.3;
                // 跑道颜色
                this.roundColor = "#87b7bd";
                // 处理跑道长度(去除左右两端空白)
                this.roundLenght = this.canvas.width - this.linew;
                // 圆球半径
                this.greenArcR = this.mapScale * greenArcR;
                this.whiteArcR = this.mapScale * whiteArcR;
                // 处理完整数据
                this.arcData = this.handleArcData()
            }

            handleArcData()
            {
                let dataTotal = this.data.length,
                endNum = this.data[dataTotal - 1]['x'],
                dataScale = this.roundLenght / endNum,
                l2start = this.linew / 2,
                mapH0_5 = this.canvas.height / 2,
                datas = [];


                // 初步处理数据
                for (var data of this.data) {
                    let item = {
                        x: (dataScale * data['x'] + l2start),
                        y: (dataScale * data['y']),
                        data: data
                    };

                    // 白点
                    item['x1'] = item.x - this.whiteArcR;
                    item['x2'] = item.x + this.whiteArcR;
                    item['y1'] = (mapH0_5 + item['y']) - this.whiteArcR;
                    item['y2'] = (mapH0_5 + item['y']) + this.whiteArcR;

                    if (data['y'] != 0) {
                        item['x1'] = item.x - this.greenArcR;
                        item['x2'] = item.x + this.greenArcR;
                        item['y1'] = (mapH0_5 + item['y']) - this.greenArcR;
                        item['y2'] = (mapH0_5 + item['y']) + this.greenArcR;
                    }

                    datas.push(item)
                }

                return datas
            }

            // 绘制场地
            createMap()
            {
                // 绘制背景
                this.ctx.fillStyle = "#D3E3E5";
                this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
                // 绘制分割线
                var lineCount = Math.ceil(this.canvas.height / this.lineh)
                for (var i = 1; i < lineCount; i++) {
                    let lineX = this.lineh * i
                    this.ctx.beginPath();
                    this.ctx.moveTo(0, lineX);
                    this.ctx.lineTo(this.canvas.width, lineX);
                    this.ctx.strokeStyle = this.lineColor;
                    this.ctx.lineWidth = this.lineWidth;
                    this.ctx.stroke();
                }

                // 绘制纵线
                lineCount = Math.ceil(this.canvas.width / this.linew)
                for (var i = 1; i < lineCount; i++) {
                    let lineY = this.linew * i
                    this.ctx.beginPath();
                    this.ctx.moveTo(lineY, 0);
                    this.ctx.lineTo(lineY, this.canvas.height);
                    this.ctx.strokeStyle = this.lineColor;
                    this.ctx.lineWidth = this.lineWidth;
                    this.ctx.stroke();
                }
            }

            // 绘制跑道
            createRound()
            {
                this.ctx.save();
                // 移动原点
                this.ctx.translate(0, (this.canvas.height - this.roundW) / 2);
                // 绘制跑道
                this.ctx.fillStyle = this.roundColor;
                this.ctx.fillRect(0, 0, this.canvas.width, this.roundW);
                this.ctx.restore();
            }

            // 处理点和圆
            createArc()
            {
                this.ctx.save();
                // 移动原点
                this.ctx.translate(0, this.canvas.height / 2);

                for (var item of this.arcData) {
                    if (item.y == 0) {
                        // 绘制白点
                        this.ctx.beginPath();
                        this.ctx.arc(item.x, 0, this.whiteArcR, 0, 2 * Math.PI);
                        this.ctx.strokeStyle = "#EEEEEE";
                        this.ctx.fillStyle = '#EEEEEE';
                        this.ctx.fill();
                        this.ctx.stroke();
                    } else {
                        // 绘制线条
                        let roundW0_5 = this.roundW / 2;
                        this.ctx.beginPath();
                        this.ctx.fillStyle = "#87b7bd";
                        if (item.y > 0)
                            this.ctx.fillRect(item.x - this.greenArcR, roundW0_5, this.greenArcR * 2, item.y - roundW0_5);
                        else
                            this.ctx.fillRect(item.x - this.greenArcR, item.y, this.greenArcR * 2, Math.abs(roundW0_5 + item.y));
                        this.ctx.stroke();

                        // 绘制绿色小点
                        this.ctx.beginPath();
                        this.ctx.arc(item.x, item.y, this.greenArcR, 0, 2*Math.PI);
                        this.ctx.strokeStyle = "green";
                        this.ctx.fillStyle = 'green';
                        this.ctx.fill();
                        this.ctx.stroke();
                    }
                }

                this.ctx.restore();
            }

            //获取鼠标在canvas画布上的位置(**不是浏览器窗口的鼠标位置)
            getMousePos(canvas, evt) {
              var rect = this.canvas.getBoundingClientRect(),
                width = $('#canvas').width(),
                height = $('#canvas').height();
                return {
                    x: evt.clientX - rect.left * (width / rect.width),
                    y: evt.clientY - rect.top * (height / rect.height)
                }
            }
        }

        new Map();

    </script>
</html>